package agents;

import gui.GraphicInterface;
import gui.Statistics;
import jade.core.AID;
import jade.core.Agent;
import jade.core.Profile;
import jade.core.ProfileImpl;
import jade.core.Runtime;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPANames.InteractionProtocol;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.FailureException;
import jade.domain.FIPAAgentManagement.NotUnderstoodException;
import jade.domain.FIPAAgentManagement.RefuseException;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import jade.proto.AchieveREInitiator;
import jade.proto.AchieveREResponder;
import jade.wrapper.AgentController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import building.AuxInfo;
import building.Cell;
import building.InfoAgent;
import building.InfoAgent.Gender;
import building.InfoGame;

/**
 * <p>
 * <B>Title:</b> Fire Evacuation
 * </p>
 * 
 * @author Carolina Arce & Caterina Bruno
 * @see agents.CoordinatorAgent
 */
public class CentralAgent extends Agent {

	/**
     *
     */
	private static final long serialVersionUID = 2738522227375621454L;
	private gui.GraphicInterface gui;
	private building.InfoGame game;
	private building.InfoGame publicGame;
	private Statistics stats;

	private AID coordinatorAgent;

	private jade.wrapper.AgentContainer ac;

	private List<AID> agentsCreated;
	private DFAgentDescription dfd;

	public CentralAgent() {
		super();
	}

	/**
	 * A message is shown in the log area of the GUI
	 * 
	 * @param str
	 *            String to show
	 */
	private void showMessage(String str) {
		if (gui != null)
			gui.showLog(str + "\n");
		System.out.println(getLocalName() + ": " + str);
	}

	private java.util.List<Cell> placeAgents(InfoGame currentGame)
			throws Exception {
		java.util.List<Cell> agents = new java.util.ArrayList<Cell>();

		Cell temp;
		// System.out.println("currentGame.nfloors" + currentGame.nfloors);
		for (int f = 0; f < currentGame.nfloors; f++) {
			for (int k = 0; k < currentGame.getInfo().getNumEvacuators(); k++) {
				try {
					InfoAgent b = new InfoAgent(1);

					b.setHealthLevels(100);
					b.reduceMob = 0;
					b.p_injured = false;

					if (male() == 1) {
						b.setMale(1);
						b.setGender(Gender.MALE);
					} else {
						b.setMale(0);
						b.setGender(Gender.FEMALE);
					}

					b.age = InfoAgent.Age.A19_30;
					b.setAgeRange(2);
					b.panic = 0;

					temp = getFreeCell(currentGame, f);
					b.setMyFloor(temp.getFloor());// the evacuator will be
													// responsible of this floor
					currentGame.getCell(temp.getRow(), temp.getColumn(), f)
							.addAgent(b);
					agents.add(currentGame.getCell(temp.getRow(),
							temp.getColumn(), f));
				} catch (Exception e) {
					System.out.print("Exception in creating evacuators"
							+ e.toString());
					e.printStackTrace();
				}
			}
		}

		/******************* END **********************/

		List<Cell> assignedCell;

		assignedCell = new ArrayList<Cell>(currentGame.getInfo()
				.getNumCivillians());
		// System.out.println("agents to create"
		// +currentGame.getInfo().getNumCivillians());
		for (int f = 0; f < currentGame.nfloors; f++) {
			for (int k = 0; k < currentGame.getInfo().getNumCivillians(); k++) {
				try {
					InfoAgent p = new InfoAgent(0);
					p.setHealthLevels(100);
					p.setReducedMob(mob_ridotta());
					p.p_injured = p_injured();
					p.panic = in_panic();


					if (p.panic == 80) {
						p.p_injured = false;
					} else {
						p.p_injured = p_injured();
					}

					if (male() == 1) {
						p.setMale(1);
						p.setGender(Gender.MALE);
					} else {
						p.setMale(0);
						p.setGender(Gender.FEMALE);
					}

					int age = calc_age();
					p.setAgeRange(age);
					if (age == 0)
						p.age = InfoAgent.Age.OVER80;
					if (age == 1)
						p.age = InfoAgent.Age.UNDER_18;
					if (age == 2)
						p.age = InfoAgent.Age.A19_30;
					if (age == 3)
						p.age = InfoAgent.Age.A31_79;

					temp = getFreeCell(currentGame, f);
					try {
						if (temp != null && !assignedCell.contains(temp)) {
							currentGame.getCell(temp.getRow(),
									temp.getColumn(), f).addAgent(p);
							agents.add(currentGame.getCell(temp.getRow(),
									temp.getColumn(), f));
							assignedCell.add(temp);
							p.setMyFloor(f);
						} else
							System.out.println("cell" + temp
									+ "already assigned");

					} catch (Exception e) {
						temp.removeAgent(p);
						agents.remove(k);
					}
				} catch (Exception e) {
					System.out.println("Exception in creating civilians"
							+ e.toString());
				}
			}
		}

		/*************
		 * PARAMEDIC ***************
		 * 
		 * try { InfoAgent b = new InfoAgent(3);
		 * 
		 * // System.out.println("cell free" + temp); //
		 * System.out.println("cell free"+temp.getRow() + "-"+temp.getColumn()+
		 * "floor:"+ f); //((currentGame.getMap())[pPiano][1][1]).addAgent(b);
		 * currentGame.getCell(0, 1, 0).addAgent(b);
		 * agents.add(currentGame.getCell(0,1, 0)); } catch(Exception e) {
		 * System.out.print("paramedic" + e.toString()); e.printStackTrace(); }
		 * 
		 * 
		 * /************* PARAMEDIC
		 ***************/

		return agents;

	}

	/**
	 * Agent setup method - called when it first come on-line. Initialization of
	 * behaviours.
	 */
	protected void setup() {

		/**** Very Important Line (VIL) *********/
		this.setEnabledO2ACommunication(true, 1);
		/****************************************/

		showMessage("Agent (" + getLocalName() + ") .... [OK]");

		// Register the agent to the DF
		ServiceDescription sd1 = new ServiceDescription();
		sd1.setType(UtilsAgents.CENTRAL_AGENT);
		sd1.setName(getLocalName());
		sd1.setOwnership(UtilsAgents.OWNER);

		dfd = new DFAgentDescription();
		dfd.addServices(sd1);
		dfd.setName(getAID());
		try {
			DFService.register(this, dfd);
			showMessage("Registered to the DF");
		} catch (FIPAException e) {
			System.err.println(getLocalName() + " registration with DF "
					+ "unsucceeded. Reason: " + e.getMessage());
			doDelete();
		}

		/**************************************************/

		if (gui == null) {
			initGame();
		}

		// init Statistics
		stats = new Statistics(game, gui);
		System.out.println("Create Statistic");
		// add behaviours

		// Search for coordinator Agent
		ServiceDescription searchCriterion = new ServiceDescription();
		searchCriterion.setType(UtilsAgents.COORDINATOR_AGENT);
		this.coordinatorAgent = UtilsAgents.searchAgent(this, searchCriterion);
		System.out.println(this.coordinatorAgent.getLocalName()
				+ "Coordinator found");
		// searchAgent is a blocking method, so we will obtain always a correct
		// AID

		// Start the simulation
		this.addBehaviour(new TurnControlBehavior(this, game.getInfo()
				.getTime()));

		// Add a behavior to receive movement orders
		MessageTemplate mt = MessageTemplate
				.MatchProtocol(UtilsAgents.PROTOCOL_MOVEMENT);
		this.addBehaviour(new MovesReceiver(this, mt));

	}

	public void initGame() {
		try {
			this.game = new InfoGame(); // object with the game data
			this.publicGame = new InfoGame(); // game data to publish
			this.publicGame.readGameFile("game.txt");
			this.game.readGameFile("game.txt");

		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("Game NOT loaded ... [KO]");
		}
		try {

			this.gui = new GraphicInterface(game, this);
			this.gui.initGUI(game);

			gui.setVisible(true);
			showMessage("Game loaded ... [OK]");
		} catch (Exception e) {
			e.printStackTrace();
		}

		agentsCreated = new ArrayList<AID>();
		/**** Agents are randomly placed ****************/
		java.util.List<Cell> agents = null;
		try {
			agents = placeAgents(this.game);
		} catch (Exception e) {
		}
		/**************************************************/
		this.game.getInfo().fillAgentsInitialPositions(agents, game);

		// Create real Agents and fill AID
		createAgents();

	}

	private void initContainer() {
		// Get a hold on JADE runtime
		Runtime rt = Runtime.instance();
		// Exit the JVM when there are no more containers around
		rt.setCloseVM(true);
		Profile p = new ProfileImpl(true);
		// System.out.println(getLocalName()+": Launching the agent container ...\n-Profile: "
		// + p);
		ac = rt.createAgentContainer(p);

	}

	private AID createAgent(String name, String type, Object args[]) {
		AID itsAID = null;
		try {
			// Create Agent in new container

			AgentController another = ac.createNewAgent(name, type, args);

			another.start();
			// Return its AID
			ServiceDescription searchCriterion = new ServiceDescription();
			searchCriterion.setName(name);
			itsAID = UtilsAgents.searchAgent(this, searchCriterion);

		} catch (jade.wrapper.StaleProxyException e) {
			System.err.println("ERROR for creating the agent. Reason: "
					+ e.toString());
			e.printStackTrace();
		} catch (Exception e4) {
			System.err.println("Error in reading config file" + e4.toString());
		}
		return itsAID;
	}

	private void updatePublicGame() {

		publicGame.setInfo(game.getInfo());

		for (int f = 0; f < game.getMap().nfloor; f++) {
			for (int r = 0; r < game.getMap().length; r++)
				for (int c = 0; c < game.getMap().width; c++) {
					if (game.getCell(r, c, f).getCellType() == Cell.FIRE) {
						double fireInt = game.getCell(r, c, f)
								.getFireIntensityUnits();
						fireInt = game.getInfo().getTurn() * (0.01) + fireInt;
						game.getCell(r, c, f).setFireIntensityUnits(fireInt);
						agents.UtilsAgents.updateSmoke(game,
								game.getCell(r, c, f));
					}

					publicGame.setCell(r, c, game.getCell(r, c, f), f);

				}
		}

	}

	/**
	 * Create Real Agents and fill AID
	 */
	protected void createAgents() {
		updatePublicGame();
		AuxInfo info = game.getInfo();
		initContainer();
		HashMap<?, ?> hm = info.getAgentsInitialPosition();
		Iterator<?> it = hm.keySet().iterator();
		int agentNumber = 1;
		while (it.hasNext()) {
			InfoAgent ia = (InfoAgent) it.next();

			// Creating the agent
			AID aid = null;
			Object[] o_c, o_e, o_p;
			o_c = new Object[5];
			o_e = new Object[5];
			o_p = new Object[1];
			o_c[0] = o_e[0] = o_p[0] = publicGame;
			try {
				switch (ia.getAgentType()) {
				case 0: {

					o_c[1] = ia.getAgeRange();
					o_c[2] = ia.male;
					o_c[3] = ia.reduceMob;
					o_c[4] = ia.panic;

					aid = createAgent(ia.getAgent() + agentNumber,
							"civilian.CivilianAgent", o_c);
					break;
				}

				case 1: {
					o_e[1] = ia.getAgeRange();
					o_e[2] = ia.male;
					o_e[3] = ia.reduceMob;
					o_e[4] = ia.panic;
					aid = createAgent(ia.getAgent() + agentNumber,
							"evacuator.EvacuatorAgent", o_e);
					break;
				}

				}
				ia.setAID(aid);
				System.err.println("AID " + aid);
				this.agentsCreated.add(aid);
			} catch (Exception e) {
				e.printStackTrace();
				showMessage("Could not create the agent specified in the game");
			}
			agentNumber++;
		}
	}

	/*** CODE CATERINA *************************************************/
	/**
	 * Calculate age to civilian agent
	 * 
	 * @return 0 if civilian is over 80 <br>
	 *         1 if civilian is under 18<br>
	 *         2 if civilian age is between 19 and 30<br>
	 *         3 if civilian is over 30<br>
	 * 
	 */
	public int calc_age() {

		double age = Math.random() * 100;
		if (age < 2)
			return 0;
		else if (age >= 2 && age < 7) // 5% di under_18
			return 1;
		else if (age >= 7 && age < 37) // 30% di under_30
			return 2;
		else
			return 3; // 63% di over_30

	}

	/**
	 * This function assign a mobility reduction to civilian with a 10% of
	 * probability.
	 * 
	 * @return 1 if civilian has a mobility reduction<br>
	 *         0 in the other case.
	 * 
	 */
	private int mob_ridotta() {
		double mr = Math.random();
		if (mr <= 0.10)
			return 1;
		return 0;

	}

	/**
	 * This function calculate if civilian is in panic striken.
	 * 
	 * @return 0 if civilian isn't in panic (in the 85 percent of cases) <br>
	 *         80 if civilian is in panic.
	 * 
	 */
	private int in_panic() {
		double mr = Math.random();
		if (mr <= 0.85)
			return 0; // no panic
		return 80; // panic_striken

	}

	/**
	 * Calculate the gender of civilian
	 * 
	 * @return 0 female <br>
	 *         1 male
	 * 
	 */
	private int male() {

		double s = Math.random() * 100;
		if (s < 50)
			return 0; // female
		return 1; // male
	}

	/**
	 * This function calculate the probability of civilian's injuring
	 * 
	 * @return true if the civilian will be a probable injured
	 */

	private boolean p_injured() {
		double s = Math.random() * 100;
		if (s < 2)
			return true; // p_injured
		return false;
	}

	/*********************************************************************/
	/*************************** OTHER CLASSES ****************************/
	/**
	 * Cyclic behavior each cycle is a game turn, also controls simulation
	 * ending
	 * 
	 * @author Carolina
	 * 
	 */
	private class TurnControlBehavior extends TickerBehaviour {

		/**
         *
         */
		private static final long serialVersionUID = -4793117331763237218L;

		public TurnControlBehavior(Agent arg0, long arg1) {
			super(arg0, arg1);
			showMessage("Turn Control Initiated timeout is "
					+ game.getInfo().getTimeout());
		}

		@Override
		protected void onTick() {
			if (gui.start) {
				// Sound myAlarm= new Sound("firealarm.mp3");
				// myAlarm.playSound();
				game.getInfo().getElapsedTime();

				game.getInfo().incrTurn();
				showMessage(" ********** Turn " + game.getInfo().getTurn()
						+ " **********");
				if (stats.isFinished()
						|| game.getInfo().getTurn() == game.getInfo()
								.getGameDuration()) {
					showMessage("Game Finished");
					this.stop();
					try {
						game.writeGameResult("result.txt", game.getMap()
								.getMap());
						System.out.println("writegame");
					} catch (IOException e) {
						showMessage("Cannot write the game results");
						e.printStackTrace();
					} catch (Exception e) {
						showMessage("General error writing game results");
						e.printStackTrace();
					}

					gui.stop = true;
					stats.show();
				} else {
					// Send updated map to all Coordinator Agent
					ACLMessage requestInicial = new ACLMessage(
							ACLMessage.REQUEST);
					requestInicial.clearAllReceiver();
					requestInicial.addReceiver(coordinatorAgent);
					requestInicial.setProtocol(InteractionProtocol.FIPA_QUERY);
					try {
						requestInicial.setContentObject(publicGame);
					} catch (Exception e) {
						System.out.println("exception central agent");
						e.printStackTrace();
					}
					// we add a behavior that sends the message and waits for an
					// answer
					updatePublicGame();
					this.myAgent.addBehaviour(new Informer(this.myAgent,
							requestInicial));
				}
			}
		}
	}

	/**
	 * 
	 * @author Carolina User to inform the coordinator agent
	 */
	class Informer extends AchieveREInitiator {

		@Override
		protected void handleAgree(ACLMessage arg0) {
			super.handleAgree(arg0);
			System.out.println("CENTRAL HandleAgree" + arg0.getSender());
		}

		@Override
		protected void handleInform(ACLMessage arg0) {
			// Auto-generated method stub
			// super.handleInform(arg0);
			System.out.println("CENTRAL HandleInform");
		}

		/**
         *
         */
		private static final long serialVersionUID = -8199039269513958089L;

		public Informer(Agent arg0, ACLMessage arg1) {
			super(arg0, arg1);
		}

	} // endof class turn control

	/*************************************************************************/

	/*************************************************************************/

	class MovesReceiver extends AchieveREResponder {
		public MovesReceiver(Agent arg0, MessageTemplate arg1) {
			super(arg0, arg1);
		}

		@Override
		protected ACLMessage prepareResponse(ACLMessage arg0)
				throws NotUnderstoodException, RefuseException {
			Cell origin = null, destination = null;
			InfoAgent ia = null;
			ACLMessage response = arg0.createReply();

			int dx = 0, dy = 0, dz = 0, x, y, f;
			moves.Movement moveOrder;
			try {
				moveOrder = (moves.Movement) arg0.getContentObject();
			} catch (UnreadableException e1) {
				moveOrder = null;
				response.setPerformative(ACLMessage.NOT_UNDERSTOOD);
				System.out.println("e1");
			}
			
			
			
			if (moveOrder != null)
				if (moveOrder.getAgent() != null)
					if (findAgent(moveOrder.getAgent()) != null)

					{
						showMessage("Received movement order from "
								+ moveOrder.getAgent().getLocalName());
						origin = findAgent(moveOrder.getAgent());
						ia = origin.getAgent();
						y = origin.getColumn();
						x = origin.getRow();
						f = origin.getFloor();
						showMessage("I have its position " + origin);
						boolean diagonal = false;
						if (moveOrder == null
								|| moveOrder.getDirection() == null) {
							response.setPerformative(ACLMessage.FAILURE);
						} else {
							System.out.println("Direction"
									+ moveOrder.getDirection());
							switch (moveOrder.getDirection()) {
							case OUT:
								dx = 0;
								dy = 0;
								dz = 0;
								stats.civEv();
								stats.incEvac4floor(0);
								stats.addAgents(ia);

								showMessage("OUT");
								break;
							case NOP:
								dx = 0;
								dy = 0;
								showMessage("NOP");
								break;
							case UP:
								dx = -1;
								showMessage("UP");
								break;
							case UPFLOOR:
								int rows = game.getNrows() - 1;
								dx = rows;
								dz = -1;
								showMessage("UPFLOOR");
								stats.incEvac4floor(1);
								break;
							case DOWNFLOOR:
								rows = 0;
								dx = rows;
								dz = 1;
								showMessage("DOWNFLOOR");
								break;
							case PUT:
								dx = 0;
								dy = 0;
								dz = 0;
								showMessage("PUT");
								break;
							case CURE:
								dx = 0;
								dy = 0;
								dz = 0;
								showMessage("CURE");
								break;
							case DOWN:
								dx = 1;
								showMessage("DOWN");
								break;
							case LEFT:
								dy = -1;
								showMessage("LEFT");
								break;
							case RIGHT:
								dy = 1;
								showMessage("RIGHT");
								break;
							case UPLEFT:
								dy = -1;
								dx = -1;
								diagonal = true;
								break;
							case UPRIGHT:
								System.out.println("Central UPRIGHT");
								dy = 1;
								dx = -1;
								diagonal = true;
								break;
							case DOWNLEFT:
								dy = -1;
								dx = 1;
								diagonal = true;
								break;
							case DOWNRIGHT:
								dy = 1;
								dx = 1;
								diagonal = true;
								break;

							case NEXTFIRE:
								Cell fireCell = (Cell) game.getInfo()
										.getFirePoints().get(0);
								game.getInfo().getFirePoints().remove(0);
								dx = fireCell.getRow();
								dy = fireCell.getColumn();
								dz = fireCell.getFloor();
								showMessage("NEXT FIRE CELL xR" + dx + "  yC"
										+ dy + "  zF" + dz);
								diagonal = true;
								break;
							}

							response.setPerformative(ACLMessage.FAILURE);
							if (y + dy >= 0)
								if (y + dy < game.getMap().width) // colonna
									if (x + dx >= 0)
										if (x + dx < game.getMap().length) // riga
											if (origin.getAgent().getLastTurn() <= game
													.getInfo().getTurn()) { // non
																			// cambiare
																			// in
																			// <
																			// !
												showMessage("Will move " + dx
														+ " " + dy + " " + dz);
												// destination=game.getMap()[f+dz][y+dy][x+dx];
												destination = game.getCell(x
														+ dx, y + dy, f + dz);
												showMessage("I have its destination "
														+ destination);
												System.out
														.print("action"
																+ moveOrder
																		.getAction());
												switch (moveOrder.getAction()) {
												case GO:
													try {
														// showMessage(origin.getAgent().getAgent()+" Moving");
														showMessage("Its a GO order");
														ia = origin.getAgent();
														// showMessage("Have the agent to remove");
														origin.removeAgent(ia);
														// showMessage("Agent Removed");
														destination
																.addAgent(ia);
														// showMessage("Agent added to new position");
														response.setPerformative(ACLMessage.AGREE);
														stats.incMovement(ia);
														showMessage(ia.getAID()
																.getLocalName()
																+ " moved from R"
																+ origin.getRow()
																+ " C"
																+ origin.getColumn()
																+ " to R"
																+ destination
																		.getRow()
																+ " C"
																+ destination
																		.getColumn());

													} catch (Exception e) {
														response.setPerformative(ACLMessage.FAILURE);
														showMessage("Could not move to that position");
														if (!origin
																.isThereAnAgent()) {
															try {
																origin.addAgent(ia);
															} catch (Exception e1) {
																showMessage("FATAL ERROR: Cannot Undo this action");
															}
															try {
																showMessage(origin
																		.getAgent()
																		.getAID()
																		.getLocalName()
																		+ " FAILED TO MOVE from R"
																		+ origin.getRow()
																		+ " C"
																		+ origin.getColumn()
																		+ " to R"
																		+ destination
																				.getRow()
																		+ " C"
																		+ destination
																				.getColumn());
															} catch (Exception e2) {
															}
															;
														}
													}
													break;
												case GOFLOOR:
													try {
														x = 0;
														y = origin.getColumn();
														System.out
																.println("going to floor "
																		+ f
																		+ dz
																		+ "from"
																		+ f);
														// destination=game.getMap()[f+dz][y+dy][x+dx];
														destination = game
																.getCell(
																		x + dx,
																		y + dy,
																		f + dz);
														showMessage(origin
																.getAgent()
																.getAgent()
																+ " Moving to f"
																+ destination
																		.getFloor()
																+ " R"
																+ destination
																		.getRow()
																+ " C"
																+ destination
																		.getColumn());
														// if (diagonal) throw
														// new Exception();
														showMessage("Its a gofloor order");
														ia = origin.getAgent();

														// showMessage("Have the agent to remove");
														origin.removeAgent(ia);
														showMessage("Agent Removed");
														// destination.setFloor(f+dz);
														// destination.setRow(game.getNrows()-1);
														destination
																.addAgent(ia);

														showMessage("Agent added to new position");
														response.setPerformative(ACLMessage.AGREE);
														stats.incMovement(ia);
														showMessage(ia.getAID()
																.getLocalName()
																+ " moved to floor from R"
																+ origin.getRow()
																+ " C"
																+ origin.getColumn()
																+ " F"
																+ origin.getFloor()
																+ " to R"
																+ destination
																		.getRow()
																+ " C"
																+ destination
																		.getColumn()
																+ " F"
																+ destination
																		.getFloor());
														// stats.scoreSavedByFloor(f);

													} catch (Exception e) {
														System.out
																.println("exception in go floor"
																		+ e.toString());
														response.setPerformative(ACLMessage.FAILURE);
													}

													break;

												case OUT:
													try {
														showMessage(origin
																.getAgent()
																.getAgentType()
																+ " going out");
														// if (diagonal) throw
														// new Exception();
														showMessage("Its a  out order");
														if(ia.out==true){
															System.out
																	.println("Agent is out!");
														}
														ia = origin.getAgent();
														showMessage("Have the agent to remove");
														origin.removeAgent(ia);
														showMessage("Agent Removed");
														ia.out = true;
														// aggiunge l'AID
														// dell'agente nella
														// lista degli agenti
														// evacuati
														if (ia.getAgentType() == InfoAgent.EVACUATOR) {
															game.addRemovedAgent(ia
																	.getAID());
															showMessage("Agent Evacuator Removed");
														}



														response.setPerformative(ACLMessage.AGREE);
														stats.incMovement(ia);

														stats.scoreSaved();

													} catch (Exception e) {
														System.out
																.println("exception in going out"
																		+ e.toString());
														response.setPerformative(ACLMessage.FAILURE);
													}
													break;
												case PUT:
													try {
														showMessage(origin
																.getAgent()
																.getAgentType()
																+ " PUT");
														ia = destination
																.getAgent();
														ia.panic = 0;
														response.setPerformative(ACLMessage.AGREE);
														stats.incMovement(ia);
														stats.setCivilian_panic(); // incrementa
																					// il
																					// numero
																					// di
																					// civili
																					// in
																					// panico
														showMessage(origin
																.getAgent()
																.getAID()
																.getLocalName()
																+ " IM NOT IN PANIC "
																+ origin.getColumn()
																+ " "
																+ origin.getRow()
																+ " to "
																+ destination
																		.getColumn()
																+ " "
																+ destination
																		.getRow());
													} catch (Exception e) {
														response.setPerformative(ACLMessage.FAILURE);
														try {
															showMessage(origin
																	.getAgent()
																	.getAID()
																	.getLocalName()
																	+ " FAILED TO PUT GARBAGE from"
																	+ origin.getColumn()
																	+ " "
																	+ origin.getRow()
																	+ " to "
																	+ destination
																			.getColumn()
																	+ " "
																	+ destination
																			.getRow());
														} catch (Exception e2) {
														}
														;
													}

													break;
												case CURE:
													try {
														showMessage(origin
																.getAgent()
																.getAgentType()
																+ " CURE");
														ia = destination
																.getAgent();
														ia.setInjured(false);
														ia.p_injured = false;
														response.setPerformative(ACLMessage.AGREE);
														stats.incMovement(ia);
														showMessage(origin
																.getAgent()
																.getAID()
																.getLocalName()
																+ " IM NOT INJURED "
																+ origin.getColumn()
																+ " "
																+ origin.getRow()
																+ " to "
																+ destination
																		.getColumn()
																+ " "
																+ destination
																		.getRow());
													} catch (Exception e) {
														response.setPerformative(ACLMessage.FAILURE);
														try {
															showMessage(origin
																	.getAgent()
																	.getAID()
																	.getLocalName()
																	+ " FAILED TO CURE CIVILIAN from"
																	+ origin.getColumn()
																	+ " "
																	+ origin.getRow()
																	+ " to "
																	+ destination
																			.getColumn()
																	+ " "
																	+ destination
																			.getRow());
														} catch (Exception e2) {
														}
														;
													}

													break;
												}
											} else {
												response.setPerformative(ACLMessage.FAILURE);
												System.err
														.println("FAILURE IN MOVING");
												System.err
														.println("Origin.LastTurn "
																+ origin.getAgent()
																		.getLastTurn()
																+ " game turn "
																+ game.getInfo()
																		.getTurn());
											}
						}
					}

			return response;
		}

		@Override
		protected ACLMessage prepareResultNotification(ACLMessage arg0,
				ACLMessage arg1) throws FailureException {
			return null;
		}

		private Cell findAgent(AID a) {
			Cell agentPosition = null;
			for (int f = 0; f < game.getMap().nfloor; f++) {
				for (int r = 0; r < game.getMap().length; r++) {
					for (int c = 0; c < game.getMap().width; c++) {
						Cell cell = game.getCell(r, c, f);
						if (cell.isThereAnAgent()) {
							if (cell.getAgent().getAID().equals(a)) {
								agentPosition = cell;
							}
						}
					}
				}
			}
			return agentPosition;
		}

		private static final long serialVersionUID = -1637780111859751489L;

	}

	public Cell getFreeCell(InfoGame currentGame, int f) {
		int x = 0;
		int y = 0;

		Random rand = new Random();
		/* Ritorna il una cella libera per posizionare gli agenti */
		// System.out.println(rand + "rand");
		boolean found = true;

		while (found) {

			x = rand.nextInt(currentGame.getNcols());
			y = rand.nextInt(currentGame.getNrows());
			if (currentGame.getCell(x, y, f).getCellType() == Cell.FREE
					&& currentGame.getCell(x, y, f).isThereAnAgent() == false) {
				if (x == 0 && y == 1 && f == 0)
					found = true; // condizione temporanea per posizionare il
									// paramedico
				found = false;
				// System.out.println(x +"-"+ y );
			}
		}

		return currentGame.getCell(x, y, f);

	}

} // endof class AgentCentral
